package com.apestech.framework.xml.sql.node;

import java.util.List;

import com.apestech.framework.db.SqlSession;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.sql.condition.ConditionMap;
import com.apestech.framework.sql.modul.FromList;
import com.apestech.framework.xml.plugin.XmlPaste;
import com.apestech.framework.xml.plugin.modul.GridHead;
import com.apestech.framework.xml.sql.XmlSqlPaste;
import com.apestech.framework.xml.sql.modul.QueryRule;
import com.apestech.framework.xml.sql.modul.QueryhTw;
import com.apestech.framework.xml.sql.modul.SqlRule;
import org.dom4j.Element;
import org.dom4j.Text;
import com.apestech.framework.sql.modul.SqlList;
import com.apestech.framework.sql.variable.SqlSection;
import com.apestech.framework.xml.pub.core.ElementUtil;

/**
 * mybatis公式语法解析器
 * @author hupo
 *
 */
public class NodeExpress extends ElementUtil {
	private Element node;
	private Element root;
	private String operator;
	private String expressAttrName=null;
	private ConditionMap input;
	private String text="";
	private SqlList param;
	private FromList fromtab;
	private QueryRule rule;
	private QueryhTw htw;
	private XmlPaste xmlPaste;
	private GridHead head;
	private SqlSession session;
	private XmlSqlPaste xmlSqlPaste;
	private JSONArray auths;
	private SqlRule sqlrule;
	private JSONObject other;
	
	public NodeExpress(Element root, Element node, ConditionMap input, SqlSession session){
		this.root=root;
		this.node=node;
		this.operator=this.node.getName().toLowerCase();
		this.input=input;
		this.session=session;
	}

	public void setFromtab(FromList fromtab) {
		this.fromtab = fromtab;
	}

	public void setExpressAttrName(String expressAttrName){
		this.expressAttrName=expressAttrName;
	}
	
	public SqlList getParam(){
		return this.param;
	}

	public QueryRule getRule() {
		return rule;
	}

	public QueryhTw getHtw() {
		return htw;
	}

	public GridHead getHead() {
		return head;
	}

	public void doExpress() throws Exception{
		this.text="";
		this.param=new SqlList();
		switch(this.operator){
			case "if": {
				execIf();
				break;
			}
			case "choose": {
				execChoose();
				break;
			}
			case "where": {
				execWhere();
				break;
			}
			case "set": {
				execSet();
				break;
			}
			case "foreach": {
				execForeach();
				break;
			}
			default:{
				xmlPaste=new XmlPaste(session);
				xmlPaste.expain(root, node);
				if(xmlPaste.getHead()!=null) head=xmlPaste.getHead();
				else if(xmlPaste.getHtw()!=null) htw=xmlPaste.getHtw();
				else if(xmlPaste.getRule()!=null) rule=xmlPaste.getRule();
				else if(xmlPaste.getXmlsql()!=null) xmlSqlPaste=xmlPaste.getXmlsql();
				else if(xmlPaste.getAuths()!=null) auths=xmlPaste.getAuths();
				else if(xmlPaste.getSqlrule()!=null) sqlrule=xmlPaste.getSqlrule();
				else{
					if( xmlPaste.getSingleResult().size()>0){
						if(other==null) other=new JSONObject();
						other.put(node.getName(), xmlPaste.getSingleResult());
					}
				}
				break;
			}
		}
	}
	
	public String getText(){
		return this.text;
	}
	
	private NodeValue getNodeValue(){
		NodeValue value;
		if(this.expressAttrName!=null){
			value=new NodeValue(this.expressAttrName);
		} else {
			value=new NodeValue();
		}
		value.setFromtab(fromtab);
		return value;
	}

	private void execIf() throws Exception{
		NodeValue value=getNodeValue();
		value.doExpress(this.node, this.input);
		this.text=this.text+value.getText();
		this.param.add(value.getParam());
	}
	
	private void execChoose() throws Exception{
		List<?> list=this.node.content();
		int len=list.size();
		for(int i=0; i<len; i++){
			String scalss=list.get(i).getClass().getName();
			if(scalss.equals("org.dom4j.tree.DefaultElement")){
				Element eml=(Element) list.get(i);
				if(eml.getName().equals("otherwise")){
					this.text=eml.getTextTrim();
					SqlSection sqlvar=new SqlSection(fromtab, input);
					sqlvar.doVar(this.text);
					this.param.add(sqlvar.getParam());
					break;
				} else {
					NodeValue value=getNodeValue();
					value.doExpress(eml, this.input);
					String v=value.getText();
					this.param.add(value.getParam());
					if(!("").equals(v)){
						this.text=v;
						break;
					}
				}
			} 
		}
	}
	
	private boolean hasLogicSymbol(String text){
		String v=leftStr(text, 4).toUpperCase().trim()+" ";
		if("AND ".equals(v)){
			return true;
		}
		v=leftStr(v, 3);
		if("OR ".equals(v)){
			return true;
		}
		return false;
	}
	
	private void whereAnd(String v){
		boolean flag=hasLogicSymbol(v);
		if("".equals(this.text)){
			this.param.add(" 1=1");
			this.text=this.text+" 1=1";
			if(!flag){
				this.param.add(" AND ");
				this.text=this.text+" AND ";
			}
		} else {
			if(!flag){
				this.param.add(" AND ");
				this.text=" AND "+this.text;
			}
		}
	}
	
	private void execWhere() throws Exception{
		List<?> list=this.node.content();
		int len=list.size();
		for(int i=0; i<len; i++){
			String scalss=list.get(i).getClass().getName();
			if(scalss.equals("org.dom4j.tree.DefaultElement")){
				Element eml=(Element) list.get(i);
				NodeValue value=getNodeValue();
				value.doExpress(eml, this.input);
				String v=value.getText();
				if(!("").equals(v)){
					whereAnd(v);
					this.param.add(value.getParam());
					this.text=this.text+v;
				}
				value=null;
			} else if(scalss.equals("org.dom4j.tree.DefaultText")){
        		Text text=(Text) list.get(i);
        		String v=text.getText().trim();
        		if(!("").equals(v)){
					whereAnd(v);
					SqlSection sqlvar=new SqlSection(fromtab, input);
					v=" "+v+" ";
					sqlvar.doVar(v);
					this.param.add(sqlvar.getParam());
					this.text=this.text+v;
				}
			}
		}
		if(!("").equals(this.text)){
			this.param.insertFirst(" WHERE ");
			this.text=" WHERE "+this.text+" ";
			this.param.add(" ");
		}
	}
	
	private String getWithOutComma(String text){
		text=text.trim();
		String v=rightStr(text, 1).toUpperCase();
		if(",".equals(v)){
			text=leftStr(text,text.length()-1);
		}
		v=leftStr(text, 1).toUpperCase();
		if(",".equals(v)){
			text=rightStr(text,text.length()-1);
		}
		return text;
	}
	
	private void execSet() throws Exception{
		List<?> list=this.node.content();
		int len=list.size();
		for(int i=0; i<len; i++){
			String scalss=list.get(i).getClass().getName();
			if(scalss.equals("org.dom4j.tree.DefaultElement")){
				Element eml=(Element) list.get(i);
				NodeValue value=getNodeValue();
				String e=eml.getTextTrim();
				e=getWithOutComma(e);
				eml.setText(e);
				value.doExpress(eml, this.input);
				String v=value.getText();
				if(!("").equals(v)){
					if(!"".equals(this.text)){
						this.text=this.text+",";
						param.add(",");
					}
					this.text=this.text+v;
					param.add(value.getParam());
					value=null;
				}
				value=null;
			} else if(scalss.equals("org.dom4j.tree.DefaultText")){
				Text text=(Text) list.get(i);
				String v=text.getText().trim();
				if(!("").equals(v)){
					v=getWithOutComma(v);
					if(!"".equals(this.text)){
						this.text=this.text+",";
						param.add(",");
					}
					SqlSection sqlvar=new SqlSection(fromtab, input);
					sqlvar.doVar(v);
					this.param.add(sqlvar.getParam());
					this.text=this.text+v;
				}
			}
		}
		if(!("").equals(this.text)){
			param.insertFirst(" SET ");
			this.text=" SET "+this.text+" ";
			param.add(" ");
		}
	}
	
	private void execForeach() throws Exception{
		NodeFor nodeFor=new NodeFor(node);
		nodeFor.setFromtab(fromtab);
		nodeFor.doExpress(input);
		if(!"".equals(nodeFor.getText())){
			this.text=nodeFor.getText()+"";
			this.param.add(nodeFor.getParam());
		}
		nodeFor=null;
	}

	public JSONObject getNodeAttr() {
		if(xmlPaste==null) return null;
		return xmlPaste.getResult();
	}

	public XmlSqlPaste getXmlSqlPaste() {
		return xmlSqlPaste;
	}

	public JSONArray getAuths() {
		return auths;
	}

	public SqlRule getSqlrule() {
		return sqlrule;
	}

	public JSONObject getOther() {
		return other;
	}
}
